package com.jintian.smart.platform.system.service;

import cn.hutool.core.collection.CollectionUtil;
import com.google.common.collect.Lists;
import com.jintian.smart.kernel.common.util.SmartBeanUtil;
import com.jintian.smart.kernel.common.util.SmartStringUtil;
import com.jintian.smart.kernel.core.code.SystemErrorCode;
import com.jintian.smart.kernel.core.domain.ResponseDTO;
import com.jintian.smart.kernel.orm.impl.AbstractEntityServiceImpl;
import com.jintian.smart.base.api.system.constant.MenuTypeEnum;
import com.jintian.smart.base.api.system.entity.MenuEntity;
import com.jintian.smart.base.api.system.form.MenuAddForm;
import com.jintian.smart.base.api.system.form.MenuBaseForm;
import com.jintian.smart.base.api.system.form.MenuUpdateForm;
import com.jintian.smart.base.api.system.view.MenuTreeVO;
import com.jintian.smart.base.api.system.view.MenuVO;
import com.jintian.smart.platform.system.mapper.MenuMapper;
import org.apache.commons.lang3.math.NumberUtils;
import org.beetl.sql.core.query.LambdaQuery;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;

import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * 菜单
 */
@Service
public class MenuService extends AbstractEntityServiceImpl<MenuMapper, MenuEntity> {
    /**
     * 添加菜单
     */
    public synchronized ResponseDTO<String> addMenu(MenuAddForm menuAddForm) {
        // 校验菜单名称
        if (this.validateMenuName(menuAddForm)) {
            return ResponseDTO.userErrorParam("菜单名称已存在");
        }
        // 校验前端权限字符串
        if (this.validateWebPerms(menuAddForm)) {
            return ResponseDTO.userErrorParam("前端权限字符串已存在");
        }
        MenuEntity menuEntity = SmartBeanUtil.copy(menuAddForm, MenuEntity.class);
        this.getEntityMapper().insert(menuEntity);
        return ResponseDTO.ok();
    }

    /**
     * 更新菜单
     */
    public synchronized ResponseDTO<String> updateMenu(MenuUpdateForm menuUpdateForm) {
        //校验菜单是否存在
        MenuEntity selectMenu = this.getById(menuUpdateForm.getMenuId());
        if (selectMenu == null) {
            return ResponseDTO.userErrorParam("菜单不存在");
        }
        if (selectMenu.getDeletedFlag() == 1) {
            return ResponseDTO.userErrorParam("菜单已被删除");
        }
        //校验菜单名称
        if (this.validateMenuName(menuUpdateForm)) {
            return ResponseDTO.userErrorParam("菜单名称已存在");
        }
        // 校验前端权限字符串
        if (this.validateWebPerms(menuUpdateForm)) {
            return ResponseDTO.userErrorParam("前端权限字符串已存在");
        }
        if (menuUpdateForm.getMenuId().equals(menuUpdateForm.getParentId())) {
            return ResponseDTO.userErrorParam("上级菜单不能为自己");
        }
        SmartBeanUtil.copyProperties(menuUpdateForm, selectMenu);
        this.updateById(selectMenu);
        return ResponseDTO.ok();
    }


    /**
     * 批量删除菜单
     */
    public synchronized ResponseDTO<String> batchDeleteMenu(List<Long> menuIdList, Long employeeId) {
        if (CollectionUtils.isEmpty(menuIdList)) {
            return ResponseDTO.userErrorParam("所选菜单不能为空");
        }
        this.deleteByMenuIdList(menuIdList, employeeId, 1);
        //孩子节点也需要删除
        this.recursiveDeleteChildren(menuIdList, employeeId);
        return ResponseDTO.ok();
    }

    private void recursiveDeleteChildren(List<Long> menuIdList, Long employeeId) {
        List<Long> childrenMenuIdList = this.selectMenuIdByParentIdList(menuIdList);
        if (CollectionUtil.isEmpty(childrenMenuIdList)) {
            return;
        }
        this.deleteByMenuIdList(childrenMenuIdList, employeeId, 1);
        recursiveDeleteChildren(childrenMenuIdList, employeeId);
    }

    /**
     * 校验菜单名称
     */
    public <T extends MenuBaseForm> Boolean validateMenuName(T menuDTO) {
        MenuEntity menu = this.getByMenuName(menuDTO.getMenuName(), menuDTO.getParentId(), 0);
        if (menuDTO instanceof MenuAddForm) {
            return menu != null;
        }
        if (menuDTO instanceof MenuUpdateForm) {
            Long menuId = ((MenuUpdateForm) menuDTO).getMenuId();
            return menu != null && menu.getMenuId().longValue() != menuId.longValue();
        }
        return true;
    }

    /**
     * 校验前端权限字符串
     *
     * @return true 重复 false 未重复
     */
    public <T extends MenuBaseForm> Boolean validateWebPerms(T menuDTO) {
        if (SmartStringUtil.isEmpty(menuDTO.getWebPerms())) {
            return false;
        }

        MenuEntity menu = this.getByWebPerms(menuDTO.getWebPerms(), 0);
        if (menuDTO instanceof MenuAddForm) {
            return menu != null;
        }
        if (menuDTO instanceof MenuUpdateForm) {
            Long menuId = ((MenuUpdateForm) menuDTO).getMenuId();
            return menu != null && menu.getMenuId().longValue() != menuId.longValue();
        }
        return true;
    }

    /**
     * 查询菜单列表
     */
    public List<MenuVO> queryMenuList(Integer disabledFlag) {
        List<MenuVO> menuVOList = this.queryMenuList(0, disabledFlag, null);
        //根据ParentId进行分组
        Map<Long, List<MenuVO>> parentMap = menuVOList.stream().collect(Collectors.groupingBy(MenuVO::getParentId, Collectors.toList()));
        return this.filterNoParentMenu(parentMap, NumberUtils.LONG_ZERO);
    }

    /**
     * 过滤没有上级菜单的菜单列表
     */
    private List<MenuVO> filterNoParentMenu(Map<Long, List<MenuVO>> parentMap, Long parentId) {
        // 获取本级菜单树List
        List<MenuVO> res = parentMap.getOrDefault(parentId, Lists.newArrayList());
        List<MenuVO> childMenu = Lists.newArrayList();
        // 循环遍历下级菜单
        res.forEach(e -> {
            List<MenuVO> menuList = this.filterNoParentMenu(parentMap, e.getMenuId());
            childMenu.addAll(menuList);
        });
        res.addAll(childMenu);
        return res;
    }

    /**
     * 查询菜单树
     *
     * @param onlyMenu 不查询功能点
     */
    public ResponseDTO<List<MenuTreeVO>> queryMenuTree(Boolean onlyMenu) {
        List<Integer> menuTypeList = Lists.newArrayList();
        if (onlyMenu) {
            menuTypeList = Lists.newArrayList(MenuTypeEnum.CATALOG.getValue(), MenuTypeEnum.MENU.getValue());
        }
        List<MenuVO> menuVOList = this.queryMenuList(0, null, menuTypeList);
        //根据ParentId进行分组
        Map<Long, List<MenuVO>> parentMap = menuVOList.stream().collect(Collectors.groupingBy(MenuVO::getParentId, Collectors.toList()));
        List<MenuTreeVO> menuTreeVOList = this.buildMenuTree(parentMap, NumberUtils.LONG_ZERO);
        return ResponseDTO.ok(menuTreeVOList);
    }

    /**
     * 构建菜单树
     */
    List<MenuTreeVO> buildMenuTree(Map<Long, List<MenuVO>> parentMap, Long parentId) {
        // 获取本级菜单树List
        List<MenuTreeVO> res = parentMap.getOrDefault(parentId, Lists.newArrayList()).stream()
                .map(e -> SmartBeanUtil.copy(e, MenuTreeVO.class)).collect(Collectors.toList());
        // 循环遍历下级菜单
        res.forEach(e -> {
            e.setChildren(this.buildMenuTree(parentMap, e.getMenuId()));
        });
        return res;
    }

    /**
     * 查询菜单详情
     */
    public ResponseDTO<MenuVO> getMenuDetail(Long menuId) {
        //校验菜单是否存在
        MenuEntity selectMenu = this.getById(menuId);
        if (selectMenu == null) {
            return ResponseDTO.error(SystemErrorCode.SYSTEM_ERROR, "菜单不存在");
        }
        if (selectMenu.getDeletedFlag() == 1) {
            return ResponseDTO.error(SystemErrorCode.SYSTEM_ERROR, "菜单已被删除");
        }
        MenuVO menuVO = SmartBeanUtil.copy(selectMenu, MenuVO.class);
        return ResponseDTO.ok(menuVO);
    }


    /**
     * 查询孩子id
     */
    public List<Long> selectMenuIdByParentIdList(List<Long> menuIdList) {
        List<MenuEntity> menuList = this.getEntityMapper().createLambdaQuery().andIn(MenuEntity::getParentId, menuIdList).select(MenuEntity::getMenuId);
        List<Long> menuIdListResult = menuList.stream().map(MenuEntity::getMenuId).collect(Collectors.toList());
        return menuIdListResult;
    }

    /**
     * 根据菜单类型查询
     *
     * @param menuType     菜单类型
     * @param deletedFlag  删除
     * @param disabledFlag 禁用
     */
    public List<MenuEntity> queryMenuByType(Integer menuType, Integer deletedFlag, Integer disabledFlag) {
        List<MenuEntity> menuList = this.getEntityMapper().createLambdaQuery()
                .andEq(MenuEntity::getDisabledFlag, disabledFlag)
                .andEq(MenuEntity::getDeletedFlag, deletedFlag)
                .andEq(MenuEntity::getMenuType, menuType).select();
        return menuList;
    }

    /**
     * 根据菜单ID查询功能点列表
     *
     * @param menuId      菜单id
     * @param menuType    菜单类型
     * @param deletedFlag 删除标记
     */
    public List<MenuEntity> getPointListByMenuId(Long menuId, Integer menuType, Integer deletedFlag) {
        List<MenuEntity> menuList = this.getEntityMapper().createLambdaQuery()
                .andEq(MenuEntity::getMenuId, menuId)
                .andEq(MenuEntity::getDeletedFlag, deletedFlag)
                .andEq(MenuEntity::getMenuType, menuType).select();
        return menuList;
    }

    /**
     * 查询菜单列表
     *
     * @param deletedFlag  是否删除
     * @param disabledFlag 是否禁用
     * @param menuTypeList 菜单类型集合
     */
    public List<MenuVO> queryMenuList(Integer deletedFlag, Integer disabledFlag, List<Integer> menuTypeList) {
        LambdaQuery<MenuEntity> query = this.getEntityMapper().createLambdaQuery()
                .andEq(MenuEntity::getDeletedFlag, deletedFlag);
        if (disabledFlag != null) {
            query.andEq(MenuEntity::getDisabledFlag, disabledFlag);
        }
        if (menuTypeList != null) {
            query.andIn(MenuEntity::getMenuType, menuTypeList);
        }
        query.desc(MenuEntity::getParentId).asc(MenuEntity::getSort);
        List<MenuEntity> menuList = query.select();
        return SmartBeanUtil.copyList(menuList, MenuVO.class);
    }

    /**
     * 根据名称查询同一级下的菜单
     *
     * @param menuName    菜单名
     * @param parentId    父级id
     * @param deletedFlag 是否删除
     */
    public MenuEntity getByMenuName(String menuName, Long parentId, Integer deletedFlag) {
        MenuEntity menu = this.getEntityMapper().createLambdaQuery()
                .andEq(MenuEntity::getMenuName, menuName)
                .andEq(MenuEntity::getDeletedFlag, deletedFlag)
                .andEq(MenuEntity::getParentId, parentId).single();
        return menu;
    }

    /**
     * 根据前端权限字符串查询菜单
     *
     * @param webPerms    前端权限字符串
     * @param deletedFlag 是否删除
     */
    public MenuEntity getByWebPerms(String webPerms, Integer deletedFlag) {
        MenuEntity menu = this.getEntityMapper().createLambdaQuery()
                .andEq(MenuEntity::getWebPerms, webPerms)
                .andEq(MenuEntity::getDeletedFlag, deletedFlag).single();
        return menu;
    }

    /**
     * 根据菜单ID删除菜单（逻辑删除）
     *
     * @param menuIdList   菜单id集合
     * @param updateUserId 操作人id
     * @param deletedFlag  是否删除
     */
    public void deleteByMenuIdList(List<Long> menuIdList, Long updateUserId, Integer deletedFlag) {
        this.getEntityMapper().createLambdaQuery().set(MenuEntity::getDeletedFlag, deletedFlag)
                .set(MenuEntity::getUpdateUserId, updateUserId)
                .andIn(MenuEntity::getMenuId, menuIdList)
                .update();
    }
}
